/**
  ******************************************************************************
  * @file    main.c
  * @author  Milandr Application Team
  * @version V2.1.0
  * @date    22/06/2023
  * @brief   Main program body.
  ******************************************************************************
  * <br><br>
  *
  * THE PRESENT FIRMWARE IS FOR GUIDANCE ONLY. IT AIMS AT PROVIDING CUSTOMERS
  * WITH CODING INFORMATION REGARDING MILANDR'S PRODUCTS IN ORDER TO FACILITATE
  * THE USE AND SAVE TIME. MILANDR SHALL NOT BE HELD LIABLE FOR ANY
  * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES RESULTING
  * FROM THE CONTENT OF SUCH FIRMWARE AND/OR A USE MADE BY CUSTOMERS OF THE
  * CODING INFORMATION CONTAINED HEREIN IN THEIR PRODUCTS.
  *
  * <h2><center>&copy; COPYRIGHT 2026 Milandr </center></h2>
  ******************************************************************************
  */

/* Includes ------------------------------------------------------------------*/
#include "stdio.h"
#include "MDR32F9Qx_rst_clk.h"
#include "MDR32F9Qx_port.h"
#include "MDR32F9Qx_utils.h"
#include "MDR32F9Qx_eeprom.h"
#include "MDR32F9Qx_bkp.h"
#include "MDR32F9Qx_timer.h"
#include "MDR32F9Qx_keypad.h"

/** @addtogroup __MDR32Fx_StdPeriph_Examples MDR32Fx StdPeriph Examples
  * @{
  */

/** @addtogroup __MDR1986VE3_EVAL MDR1986VE3 Evaluation Board
  * @{
  */

/** @addtogroup KEYPAD_IT_VE3 KEYPAD_IP
 *  @{
 */

/* Private macro -------------------------------------------------------------*/
#if defined (_USE_DEBUG_UART_)
    #define DEBUG_PRINTF(...) printf(__VA_ARGS__)
#else
    #define DEBUG_PRINTF(...)
#endif /* #if defined _USE_DEBUG_UART_ */

/* Private variables ---------------------------------------------------------*/
static PORT_InitTypeDef PORT_InitStructure;
static TIMER_CntInitTypeDef TIMER_CntInitStruct;

/* Private function prototypes -----------------------------------------------*/
void ClockConfigure(void);

/* Private functions ---------------------------------------------------------*/

/**
  * @brief  Keupad interrupt handler.
  * @param  None
  * @retval None
  */
void KEYPAD_IRQHandler(void)
{
    uint32_t key1, key2;

    /* Disable IT from KEYPAD */
    KEYPAD_ITCmd(DISABLE);

    /* Disable KEYPAD */
    KEYPAD_Cmd(DISABLE);

    if (KEYPAD_GetFlagStatus(KEYPAD_FLAG_INTF))
    {
        KEYPAD_ClearFlag(KEYPAD_FLAG_INTF);
        if (KEYPAD_GetFlagStatus(KEYPAD_FLAG_PCHATF))
        {
            KEYPAD_ClearFlag(KEYPAD_FLAG_PCHATF);
            if (KEYPAD_GetFlagStatus(KEYPAD_FLAG_PT1F))
            {
                /* */
                KEYPAD_ClearFlag(KEYPAD_FLAG_PT1F);
                key1 = KEYPAD_GetPressedFirstKey();
                DEBUG_PRINTF("Pressed the first button with the code %d\r\n", key1);
            }
            if (KEYPAD_GetFlagStatus(KEYPAD_FLAG_PT2F))
            {
                /* */
                KEYPAD_ClearFlag(KEYPAD_FLAG_PT2F);
                key2 = KEYPAD_GetPressedSecondKey();
                DEBUG_PRINTF("Pressed the second button with the code %d\r\n", key2);
            }
        }
    }
    /* Reset timer counter */
    TIMER_SetCounter(MDR_TIMER1, 0);
    /* Enable timer */
    TIMER_Cmd(MDR_TIMER1, ENABLE);
}

/**
  * @brief  Main program.
  * @param  None
  * @retval None
  */
int main(void)
{
    KEYPAD_InitTypeDef KEYPAD_InitStruct;

    /* Configure CPU clock */
    ClockConfigure();

#if defined (_USE_DEBUG_UART_)
    STDIO_Init();
#endif /* #if defined (_USE_DEBUG_UART_) */
    /* Setting the interval timer to 200 ms */

    RST_CLK_PCLKcmd(RST_CLK_PCLK_TIMER1, ENABLE);
    TIMER_BRGInit(MDR_TIMER1,TIMER_HCLKdiv1);
    TIMER_DeInit(MDR_TIMER1);
    TIMER_CntStructInit(&TIMER_CntInitStruct);
    TIMER_CntInitStruct.TIMER_Prescaler = 80;
    TIMER_CntInitStruct.TIMER_Period    = 200000;
    TIMER_CntInit(MDR_TIMER1, &TIMER_CntInitStruct);
    TIMER_CntEventSourceConfig(MDR_TIMER1, TIMER_EvSrc_TM1);

    /* Enable CLK for the PORTE */
    RST_CLK_PCLKcmd(RST_CLK_PCLK_PORTE, ENABLE);
    /* Enable CLK for the PORTH */
    RST_CLK_PCLK2cmd(RST_CLK_PCLK2_PORTH, ENABLE);

    /* Reset setting for the PORTE */
    PORT_DeInit(MDR_PORTE);

    /* Config the PORTE at the reads port of the KEYPAD. */
    PORT_StructInit(&PORT_InitStructure);
    PORT_InitStructure.PORT_Pin     = (PORT_Pin_3 | PORT_Pin_4 | PORT_Pin_5);
    PORT_InitStructure.PORT_MODE    = PORT_MODE_DIGITAL;
    PORT_InitStructure.PORT_FUNC    = PORT_FUNC_OVERRID;
    PORT_InitStructure.PORT_SPEED   = PORT_SPEED_MAXFAST;
    PORT_InitStructure.PORT_OE      = PORT_OE_IN;
    PORT_InitStructure.PORT_PULL_UP = PORT_PULL_UP_OFF;
    PORT_Init(MDR_PORTE, &PORT_InitStructure);

    /* Config the PORTE at the reads port of the KEYPAD. */
    PORT_DeInit(MDR_PORTH);
    PORT_InitStructure.PORT_Pin  = (PORT_Pin_0 | PORT_Pin_1 | PORT_Pin_2 | PORT_Pin_3);
    PORT_InitStructure.PORT_FUNC = PORT_FUNC_MAIN;
    PORT_InitStructure.PORT_OE   = PORT_OE_OUT;;
    PORT_Init(MDR_PORTH, &PORT_InitStructure);

    /* Enable peripheral clocks */
    RST_CLK_PCLK2cmd(RST_CLK_PCLK2_KEYBOARD, ENABLE);

    /* Reset the current settings of the KEYPAD */
    KEYPAD_DeInit();
    /* Config the CLK DIV for the KEYPAD. */
    KEYPAD_BRGInit(KEYPAD_BRG_1024);
    /* Init the KEYPAD_InitStruct. */
    KEYPAD_StructInit(&KEYPAD_InitStruct);
    KEYPAD_InitStruct.KeyRow                  = KEYPAD_KEY_ROW_3;
    KEYPAD_InitStruct.KeyColumn               = KEYPAD_KEY_COLUMN_4;
    KEYPAD_InitStruct.DelayBetweenScansConfig = KEYPAD_DELAY_BETWEEN_SCANS_2048_CYCLES;
    KEYPAD_InitStruct.DelayBetweenScansState  = ENABLE;
    KEYPAD_InitStruct.ContactChatteringState  = ENABLE;
    KEYPAD_InitStruct.ContactChatteringTimer  = KEYPAD_CONTACT_CHATTERING_TIMER_2048_CYCLES;

    /* Init the KEYPAD. */
    KEYPAD_Init(&KEYPAD_InitStruct);

    /* Enable IT from the KEYPAD. */
    NVIC_EnableIRQ(KEYPAD_IRQn);

    /* Start timer. */
    TIMER_Cmd(MDR_TIMER1, ENABLE);

    /* Infinite loop */
    while(1)
    {
        while(TIMER_GetFlagStatus(MDR_TIMER1, TIMER_STATUS_CNT_ARR) != SET) {}
        TIMER_ClearFlag(MDR_TIMER1, TIMER_STATUS_CNT_ARR);
        TIMER_Cmd(MDR_TIMER1, DISABLE);
        /* Enable IT from the KEYPAD. */
        KEYPAD_ITCmd(ENABLE);
        /* Enable the KEYPAD */
        KEYPAD_Cmd(ENABLE);
    }
}

/**
  * @brief  Configure CPU clock.
  * @param  None
  * @retval None
  */
void ClockConfigure(void)
{
    /* Reset the clock system settings */
    RST_CLK_DeInit();

    /* Enable HSE (High Speed External) clock */
    RST_CLK_HSEconfig(RST_CLK_HSE_ON);
    while(RST_CLK_HSEstatus() != SUCCESS) {}

    /* Configures the CPU_PLL clock source (CPU_CLK = HSE_CLK * 10 = 8 MHz * 10 = 80 MHz) */
    RST_CLK_CPU_PLLconfig(RST_CLK_CPU_PLLsrcHSEdiv1, RST_CLK_CPU_PLLmul10);
    /* Enables the CPU_PLL */
    RST_CLK_CPU_PLLcmd(ENABLE);
    while(RST_CLK_CPU_PLLstatus() == ERROR) {}

    /* Select the CPU_PLL output as input for CPU_C2_SEL */
    RST_CLK_CPU_PLLuse(ENABLE);
    /* Set CPUClk Prescaler (CPU_C3_SEL = CPU_C2) */
    RST_CLK_CPUclkPrescaler(RST_CLK_CPUclkDIV1);

    /* Enables the RST_CLK_PCLK_EEPROM */
    RST_CLK_PCLKcmd(RST_CLK_PCLK_EEPROM, ENABLE);
    /* Sets the code latency value (CPU_CLK up to 100 MHz) */
    EEPROM_SetLatency(EEPROM_Latency_3);
    /* Disables the RST_CLK_PCLK_EEPROM */
    RST_CLK_PCLKcmd(RST_CLK_PCLK_EEPROM, DISABLE);

    /* Enables the RST_CLK_PCLK_BKP */
    RST_CLK_PCLKcmd(RST_CLK_PCLK_BKP, ENABLE);
    /* Setting the parameters of the voltage regulator SelectRI and LOW in the BKP controller (CPU_CLK = 80 MHz) */
    BKP_DUccMode(BKP_DUcc_upto_80MHz);

    /* Select the CPU clock source */
    RST_CLK_CPUclkSelection(RST_CLK_CPUclkCPU_C3);

    SystemCoreClockUpdate();
}

/**
  * @brief  Reports the source file name, the source line number
  *         and expression text (if USE_ASSERT_INFO == 2) where
  *         the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @param  expr:
  * @retval None
  */
#if (USE_ASSERT_INFO == 1)
void assert_failed(uint8_t* file, uint32_t line)
{
    /* User can add his own implementation to report the source file name and line number.
       Ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */

    /* Infinite loop */
    while(1) {}
}
#elif (USE_ASSERT_INFO == 2)
void assert_failed(uint8_t* file, uint32_t line, const uint8_t* expr)
{
    /* User can add his own implementation to report the source file name, line number and
       expression text.
       Ex: printf("Wrong parameters value (%s): file %s on line %d\r\n", expr, file, line) */

    /* Infinite loop */
    while(1) {}
}
#endif /* USE_ASSERT_INFO */

/** @} */ /* End of group KEYPAD_IT_VE3 */

/** @} */ /* End of group __MDR1986VE3_EVAL */

/** @} */ /* End of group __MDR32Fx_StdPeriph_Examples */

/******************* (C) COPYRIGHT 2026 Milandr ********************************
*
* END OF FILE main.c */

